#include <map>
using std::map;
#include <string>
using std::string;

#include "sysdef.h"
#include "logger.h"
#include "config.h"

/////////////////////////////////   appversion      ///////////////////////////////////

string appversion = "APP V1.0.000";

///////////////////////////////   exepath exename   //////////////////////////////////

string g_exepath = "";

string g_exename = "";

string replace_separator(const char* inbuf, const char srcdelim, const char destdelim)
{
    string temp = inbuf;

    uint size = (uint)(temp.size());
    
    while(size != 0)
    {
        --size;

        if(srcdelim == temp[size])
            temp[size] = destdelim;
    }

    return temp;
}

void parse_moudle_path()
{
    char exepath[1024] = { 0 };

#ifdef WIN32
    GetModuleFileNameA(NULL, (char*)&exepath, 1023);
#else
    readlink("/proc/self/exe", exepath, 1023);
#endif

    strcpy(exepath, replace_separator(exepath, '\\', '/').c_str());

    char* temp = strrchr(exepath, '/'); *temp = '\0';

    g_exepath = exepath;

    g_exename = temp + 1;
}

/////////////////////////////////   create_dir      ///////////////////////////////////

void create_dir(const char* input)
{
    string path = g_exepath + input;

#ifdef WIN32

    ::CreateDirectory(path.c_str(), NULL);

#else

    mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

#endif
}

/////////////////////////////////       console        ///////////////////////////////////

int write_console(const char* inbuf, int inlen)
{
    int written = 0; 

#ifdef WIN32

    if(0 == inlen) inlen = strlen(inbuf);

    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), inbuf, inlen, (LPDWORD)&written, NULL);

#endif

    return written;
}

/////////////////////////////////       main        ///////////////////////////////////

typedef map<string, string> arg_map;

arg_map g_argmap;

void get_arg_params(int argc, char** argv)
{
    char exepath[1024] = { 0 }; strcpy(exepath, argv[0]);

    strcpy(exepath, replace_separator(exepath, '\\', '/').c_str());

    char* temp = strrchr(exepath, '/');
    
    if(NULL == temp) return;
    
    *temp = '\0';

    if(g_exepath.empty())
    {
        g_exepath = exepath;
        g_exename = temp + 1;
    }

    for(int index = 1; index < argc; ++index)
    {
        if('-' == argv[index][0])
        {
            char key[2] = { 0 }; key[0] = argv[index][1];

            const char* value = &argv[index][2];

            g_argmap[key] = value;
        }
    }
}

CConfig::CConfig()
: m_block(NULL)
{
    m_buffer = "";
}

CConfig::~CConfig()
{
}

bool CConfig::ParseConfig(const char* input, ushort inlen)
{
    if(!IsEmpty()) return false;

    m_buffer = input;

    CXmlBuffer buffer(input, inlen);

    if(buffer.ToBlock(this) <= 0)
        return false;
    
    m_block = FindChild(XML_SIGN_NODE, "CONFIG");

    return NULL != m_block;
}

string CConfig::GetWorkType()
{
    if(NULL == m_block) return false;

    CByteBlock* block = m_block->FindChild(XML_SIGN_ATTR, "type");

    if(NULL == block) return false;

    return block->GetBlockValue();
}

int CConfig::GetWorkThreadCount()
{
    if(NULL == m_block) return false;

    return m_block->GetChildCount(XML_SIGN_NODE, "WORKER");
}

#define FIND_CHILD(sign,name,index)      if(NULL == m_block) return false; \
                                         CByteBlock* block = m_block->FindChild(sign, name, index); \
                                         if(NULL == block) return false; \
                                         CByteBlock* child = NULL;

#define RETURN_CONFIG_DATA(sign,name)    child = block->FindChild(sign, name); \
                                         if(NULL == child) return false; \
                                         return child->GetBlockValue();

#define RETURN_CONFIG_INT(sign,name)     child = block->FindChild(sign, name); \
                                         if(NULL == child) return false; \
                                         return atoi(child->GetBlockValue().c_str());

#define GET_CONFIG_DATA(sign,name,value) child = block->FindChild(sign, name); \
                                         if(NULL == child) return false; \
                                         value = child->GetBlockValue();

#define GET_CONFIG_INT(sign,name,value)  child = block->FindChild(sign, name); \
                                         if(NULL == child) return false; \
                                         value = atoi(child->GetBlockValue().c_str());

string CConfig::GetWorkIp(int index)
{
    FIND_CHILD(XML_SIGN_NODE, "WORKER", index);

    RETURN_CONFIG_DATA(XML_SIGN_NODE, "IP");
}

ushort CConfig::GetWorkPort(int index)
{
    FIND_CHILD(XML_SIGN_NODE, "WORKER", index);

    RETURN_CONFIG_INT(XML_SIGN_NODE, "PORT");
}

bool CConfig::GetSqlInfo(SqlInfo& sqlinfo)
{
    FIND_CHILD(XML_SIGN_NODE, "MYSQL", 1);

    GET_CONFIG_INT(XML_SIGN_NODE, "PORT", sqlinfo._port);

    GET_CONFIG_DATA(XML_SIGN_NODE, "IP", sqlinfo._ip);

    GET_CONFIG_DATA(XML_SIGN_NODE, "USERNAME", sqlinfo._username);

    GET_CONFIG_DATA(XML_SIGN_NODE, "USERPWD", sqlinfo._userpwd);

    GET_CONFIG_DATA(XML_SIGN_NODE, "DBNAME", sqlinfo._dbname);

    return true;
}
